package me.lwn.auth.security.config.annotation.authentication.configuration;

import me.lwn.auth.security.web.authentication.SmsVerifyService;
import me.lwn.auth.security.web.authentication.dao.SmsAuthenticationProvider;
import org.springframework.context.ApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.authentication.configuration.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * 初始化SmsAuthenticationProvider到ProviderManager 中的parent中
 * AuthenticationManager 在最初初始化时，定义了parentAuthenticationManager，
 * 会将DaoAuthenticationProvider初始化到ProviderManager的parentAuthenticationManager中，
 * 此处就是将SmsAuthenticationProvider 也初始化到parentAuthenticationManager中，
 * 在执行 AuthenticationManager 校验时如果不通过，会使用parentAuthenticationManager中的provider继续校验
 * {@link AuthenticationConfiguration}
 *
 * @see AuthenticationConfiguration#getAuthenticationManager()
 */
@Order(InitializeSmsUserDetailsBeanManagerConfigurer.DEFAULT_ORDER)
public class InitializeSmsUserDetailsBeanManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {

    static final int DEFAULT_ORDER = Ordered.LOWEST_PRECEDENCE - 4999;

    private final ApplicationContext context;

    public InitializeSmsUserDetailsBeanManagerConfigurer(ApplicationContext context) {
        this.context = context;
    }

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth.apply(new InitializeSmsUserDetailsManagerConfigurer());
    }

    class InitializeSmsUserDetailsManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {

        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {

            UserDetailsService userDetailsService = getBeanOrNull(UserDetailsService.class);
            SmsVerifyService smsVerifyService = getBeanOrNull(SmsVerifyService.class);
            if (userDetailsService == null || smsVerifyService == null) {
                return;
            }
            SmsAuthenticationProvider provider = new SmsAuthenticationProvider(userDetailsService, smsVerifyService);
            auth.authenticationProvider(provider);
        }

        private <T> T getBeanOrNull(Class<T> type) {
            String[] beanNames = InitializeSmsUserDetailsBeanManagerConfigurer.this.context.getBeanNamesForType(type);
            if (beanNames.length != 1) {
                return null;
            }
            return InitializeSmsUserDetailsBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
        }

    }

}
